﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using WIA;

namespace PDFMerge
{
    /// <summary>
    /// Entry Point and main class responsible for executing all the code in single thread
    /// </summary>
    public partial class Form1 : Form
    {
        //Stores the index and SimplePDFDocs. Index is the order in which the PDF docs will be merged
        public Dictionary<int, SimplePDFDoc> documentList = new Dictionary<int, SimplePDFDoc>();
        
        //Constructor
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Invokes the WIA for getting images/data from scanner/camera. Returns an Image or null if cancelled
        /// </summary>
        /// <returns>Image</returns>
        private Image getImageFromScanner()
        {
            const string wiaFormatJPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}";
            CommonDialogClass wiaDiag = new CommonDialogClass();
            WIA.ImageFile wiaImage = null;

            wiaImage = wiaDiag.ShowAcquireImage(
                WiaDeviceType.UnspecifiedDeviceType,
                WiaImageIntent.GrayscaleIntent,
                WiaImageBias.MaximizeQuality,
                wiaFormatJPEG, true, true, false);
            
            if (wiaImage != null)
            {
                WIA.Vector vector = wiaImage.FileData;
                Image i = Image.FromStream(new MemoryStream((byte[])vector.get_BinaryData()));
                return i;
                //i.Save("c:\\temp\\test.jpg");
            }
            else { return null; }
        }

        /// <summary>
        /// Adds the SimplePDFDoc to the GUI (dataGridView) and more importantly to the documentList
        /// </summary>
        /// <param name="doc">The SimplePDFDoc that should be added</param>
        private void addDocumentToList(SimplePDFDoc doc)
        {
            DataGridViewRow newRow = new DataGridViewRow();
            newRow.CreateCells(dataGridView1);
            //newRow.Cells[0].Value = "View";                                                         //View PDF btn 0
            
            if (!(String.IsNullOrEmpty(doc.FriendlyName)))
            {
                newRow.Cells[1].Value = doc.FriendlyName;                                               //File Name 1
            } else { newRow.Cells[1].Value = new System.IO.FileInfo(doc.FilePath).Name.ToString(); }    //File Name 1
            
            
            newRow.Cells[2].Value = doc.NumPages.ToString();                                        //Number of pages 2
            newRow.Cells[3].Value = doc.PageSize;                                                   //Page Size 3
            //newRow.Cells[4].Value = "Move Up";                                                      //Move Up Button 4
            //newRow.Cells[5].Value = "Move Down";                                                    //Move Down Button 5
            //newRow.Cells[6].Value = "Remove";                                                       //Delete Button 6
            newRow.Cells[7].Value = doc.FilePath;                                                   //Full File Path 7
            int rowIndex = dataGridView1.Rows.Add(newRow);

            documentList.Add(rowIndex, doc);
            checkSaveButtonStatus();
        }

        /// <summary>
        /// Event that occurs when a user clicks on a cell's content in the DataGridView.
        /// This handles the moving/removal and viewing of documents in the list
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0)
            {
                switch (e.ColumnIndex)
                {
                    case 0: //View
                        {
                            documentList[e.RowIndex].OpenDocument();
                            break;
                        }
                    case 4: //MoveUp
                        {
                            //Make sure we aren't already at the top row
                            if (e.RowIndex != 0)
                            {
                                DataGridViewRow tmp = dataGridView1.Rows[e.RowIndex];

                                //Move the DataGrid
                                dataGridView1.Rows.RemoveAt(e.RowIndex);
                                dataGridView1.Rows.Insert(e.RowIndex - 1, tmp);

                                //Update the Dictonary list
                                //Have to create a new one since I don't know how to shift the keys :(
                                Dictionary<int, SimplePDFDoc> newList = new Dictionary<int, SimplePDFDoc>();
                                for (int i = 0; i <= documentList.Count - 1; i++)
                                {
                                    if (i == e.RowIndex - 1)
                                    {
                                        //Grab row we want to move
                                        newList.Add(i, documentList[e.RowIndex]);
                                    }
                                    else if (i == e.RowIndex)
                                    {
                                        //Grab previous row from old collection
                                        newList.Add(i, documentList[e.RowIndex - 1]);
                                    }
                                    else
                                    {
                                        newList.Add(i, documentList[i]);
                                    }
                                }
                                //Save new List
                                documentList = newList;
                            }
                            break;
                        }
                    case 5: //MoveDown
                        {
                            //Make sure we are not already at the last row
                            if (e.RowIndex != dataGridView1.Rows.Count - 1)
                            {
                                //Grid we want to move
                                DataGridViewRow tmp = dataGridView1.Rows[e.RowIndex];

                                //Move the DataGrid
                                dataGridView1.Rows.RemoveAt(e.RowIndex);
                                dataGridView1.Rows.Insert(e.RowIndex + 1, tmp);

                                //Update the Dictonary list
                                //Have to create a new one since I don't know how to shift the keys :(
                                Dictionary<int, SimplePDFDoc> newList = new Dictionary<int, SimplePDFDoc>();
                                for (int i = 0; i <= documentList.Count - 1; i++)
                                {
                                    //Grab row we want to move down
                                    if (i == e.RowIndex)
                                    {
                                        //add the one below first
                                        newList.Add(i, documentList[e.RowIndex + 1]);
                                    }
                                    //Grab previous row from old collection to replace the one were moving
                                    else if (i == e.RowIndex + 1)
                                    {
                                        //Add the list below the one we are moving
                                        newList.Add(i, documentList[e.RowIndex]);

                                    }
                                    //All other documents remain in the same order
                                    else
                                    {
                                        newList.Add(i, documentList[i]);
                                    }
                                }
                                //Save new List
                                documentList = newList;
                            }
                            break;
                        }
                    case 6: //Remove
                        {

                            if (checkbox_ConfirmDelete.Checked)
                            {
                                DialogResult result = MessageBox.Show(
                                    String.Format("Are you sure you want to remove\r\n\"{0}\"", dataGridView1.Rows[e.RowIndex].Cells[1].Value),
                                    "Remove from list?",
                                    MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Warning,
                                    MessageBoxDefaultButton.Button2);

                                if (result == DialogResult.No)
                                {
                                    break;
                                }
                            }

                            //Move the data grid view
                            dataGridView1.Rows.RemoveAt(e.RowIndex);
                            //Update the Dictonary list
                            //Have to create a new one since I don't know how to shift the keys :(
                            Dictionary<int, SimplePDFDoc> newList = new Dictionary<int, SimplePDFDoc>();
                            for (int i = 0; i <= documentList.Count - 1; i++)
                            {
                                if (i == e.RowIndex)
                                {
                                    //Grab previous row from old collection
                                    //newList.Add(i, documentList[e.RowIndex + 1]);
                                }
                                else if (i > e.RowIndex)
                                {
                                    newList.Add(i - 1, documentList[i]);
                                }
                                else
                                {
                                    newList.Add(i, documentList[i]);
                                }
                            }
                            //Save new List
                            documentList = newList;
                            break;
                        }
                    default:
                        {
                            //Do nothing
                        }
                        break;
                }
            }
            //Check the button status, just to be safe
            checkSaveButtonStatus();
        }
        
        /// <summary>
        /// A routine that determines if the "Merge PDF" button should be enabled or disabled
        /// This should be called whenever we add or remove a document from the list
        /// </summary>
        private void checkSaveButtonStatus()
        {
            if (documentList.Count > 0)
            {
                btn_save.Enabled = true;
            }
            else { btn_save.Enabled = false; }
        }

        #region Button Clicks

        /// <summary>
        /// Handles the open file dialog for importing PDF into the program
        /// </summary>
        /// <param name="sender">Button Control</param>
        /// <param name="e">EventArgs</param>
        private void button1_Click(object sender, EventArgs e)
        {
            openFileDialog1.ShowDialog();
        }

        /// <summary>
        /// Opens the Save File Dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_save_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
        }


        /// <summary>
        /// Handles the "About Box"
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click_1(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox();
            about.ShowDialog(this);
        }

        /// <summary>
        /// Handles the Scanner Image button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_scan_Click(object sender, EventArgs e)
        {
            try
            {
                Image tmp = getImageFromScanner();
                if (tmp != null)
                {
                    ImportImage scanForm = new ImportImage(tmp);
                    DialogResult result = scanForm.ShowDialog(this);
                    if (result == DialogResult.OK)
                    {
                        addDocumentToList(new SimplePDFDoc(scanForm.pdfDoc, scanForm.PDFName));
                    }
                }
            }
            catch (System.Runtime.InteropServices.COMException comException)
            {
                string errorMessage = String.Empty;
                if (comException.ErrorCode == -2145320939)
                {
                    errorMessage = "No devices are available or supported";
                }
                else { errorMessage = "Problem communicating with device"; }
                
                MessageBox.Show(
                    String.Format("Reason: {0}", errorMessage),
                    "Unable to get image!",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    String.Format("Reason: {0}", ex.Message),
                    "Unable to get image!",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }
        #endregion

        #region File Dialog Events

        /// <summary>
        /// Event that occurs when the user clicks "OK" on the save file dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            try
            {
                List<SimplePDFDoc> documents = documentList.Values.ToList<SimplePDFDoc>();
                PDFMerger.PerformMerge(documents, ((SaveFileDialog)sender).FileName);

                if (checkbox_OpenFileWhenDone.Checked)
                {
                    Process proc = new Process();
                    proc.StartInfo.FileName = ((SaveFileDialog)sender).FileName;
                    proc.Start();
                }

                if (checkbox_OpenFolderWhenDone.Checked)
                {
                    Process proc = new Process();
                    proc.StartInfo.FileName = "explorer.exe";
                    FileInfo fi = new FileInfo(((SaveFileDialog)sender).FileName);
                    proc.StartInfo.Arguments = fi.DirectoryName;
                    proc.Start();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                   String.Format(
                       "Unable to save/merge document(s):\r\n{0}", ex.Message),
                   "Unable to merge document(s)",
                   MessageBoxButtons.OK,
                   MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Occurs when the user clicks "ok" on the openFileDialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            try
            {
                if (((OpenFileDialog)sender).FileNames.Count() > 1)
                {
                    string[] files = ((OpenFileDialog)sender).FileNames;
                    foreach (string file in files)
                    {
                        addDocumentToList(new SimplePDFDoc(file));
                    }
                }
                else if (((OpenFileDialog)sender).FileNames.Count() == 1)
                {
                    addDocumentToList(new SimplePDFDoc(((OpenFileDialog)sender).FileName));
                }
                else { throw new Exception("No files selected"); }
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    String.Format(
                        "Unable to open document(s):\r\n{0}", ex.Message),
                    "Unable to open document(s)",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
            checkSaveButtonStatus();
        }
        #endregion

        #region DrapNDrop Events
        /// <summary>
        /// Event that occurs when a user drops a file onto the UI.
        /// This will check to see if drop is PDF doc and add it, or Image then try to import
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dataGridView1_DragDrop(object sender, DragEventArgs e)
        {
            string errorString = String.Empty;
            string[] data = (string[])e.Data.GetData(DataFormats.FileDrop);
            foreach (string item in data)
            {
                try
                {
                    //First try to see if PDF doc
                    addDocumentToList(new SimplePDFDoc(item));
                }
                catch (Exception ex1)
                {
                    try
                    {
                        errorString += ex1.Message;
                        //Second try to see if image
                        ImportImage siForm = new ImportImage(Image.FromFile(item));
                        siForm.ShowDialog(this);
                        DialogResult result = siForm.DialogResult;
                        if (result == System.Windows.Forms.DialogResult.OK)
                        {
                            addDocumentToList(new SimplePDFDoc(siForm.pdfDoc,siForm.PDFName));
                        }
                    }
                    catch (Exception ex2)
                    {
                        errorString += "\r\n--or--\r\n" + ex2.Message;
                        MessageBox.Show(
                            String.Format("Unable to import the following file\r\n{0}\r\nSupposed reason: {1}", item,errorString),
                            "Error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                    }
                }
                errorString = String.Empty;
            }
        }

        /// <summary>
        /// Cursor effect for Drag and Drop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dataGridView1_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.All;
        }
        #endregion
        
    }
}
